import logging
import os
import subprocess
import threading
import time
import requests

from config import Config
from script_utils import execute_script

logger = logging.getLogger("bgw")


class DeviceManager:
    """设备管理器类"""
    
    def __init__(self, config_manager):
        """
        初始化设备管理器
        
        Args:
            config_manager: 配置管理器实例
        """
        self.config_manager = config_manager
        self.monitor_thread = None
        self.is_monitoring = False
    
    def report_to_server(self, config_data):
        """上报配置数据到服务器"""
        try:
            report_data = {
                "cmdType":"config",
                "params": config_data
            }
            response = requests.post(Config.report_ip_url, json=report_data, timeout=10)
            if response.status_code == 200:
                logger.info("配置数据上报成功")
                return True
            else:
                logger.error(f"配置数据上报失败，状态码: {response.status_code}")
                return False
        except Exception as e:
            logger.error(f"上报配置数据时发生异常: {str(e)}")
            return False
    
    def monitor_config_changes(self):
        """监控配置变化的线程函数"""
        logger.info("开始监控配置变化")
        last_config = None
        
        while self.is_monitoring:
            try:
                # 获取当前配置
                current_config = self.config_manager.get_all_param()
                
                # 检查是否有配置变化
                if current_config != last_config and current_config:
                    logger.info("检测到配置变化，准备上报")
                    if self.report_to_server(current_config):
                        last_config = current_config
                    else:
                        logger.warning("上报失败，将在下次检测时重试")
                
                # 等待5秒后再次检测
                time.sleep(5)
                
            except Exception as e:
                logger.error(f"监控配置变化时发生异常: {str(e)}")
                time.sleep(5)
        
        logger.info("配置监控线程已停止")
    
    def start_layer2_mode(self):
        """启动二层模式"""
        try:
            # 启动前删除配置文件
            try:
                if os.path.exists(Config.config_result_file_path):
                    os.remove(Config.config_result_file_path)
                    logger.info(f"已删除配置文件: {Config.config_result_file_path}")
                else:
                    logger.info(f"配置文件不存在，无需删除: {Config.config_result_file_path}")
            except Exception as e:
                logger.warning(f"删除配置文件时发生异常: {str(e)}")
                # 继续执行，不因为删除文件失败而阻止启动
            
            # 启动ng_detect程序
            if not os.path.exists(Config.ng_detect_app_path):
                logger.error(f"ng_detect程序不存在: {Config.ng_detect_app_path}")
                return {"_status": 1, "_msg": f"ng_detect程序不存在: {Config.ng_detect_app_path}"}
            
            # 使用nohup启动ng_detect程序
            cmd = f"nohup {Config.ng_detect_app_path} > /dev/null 2>&1 &"
            result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
            
            if result.returncode == 0:
                logger.info("ng_detect程序启动成功")
                
                # 启动监控线程
                if not self.is_monitoring:
                    self.is_monitoring = True
                    self.monitor_thread = threading.Thread(target=self.monitor_config_changes, daemon=True)
                    self.monitor_thread.start()
                    logger.info("配置监控线程启动成功")
                
                return {"_status": 0, "_msg": "二层模式启动成功，监控线程已启动"}
            else:
                logger.error(f"ng_detect程序启动失败: {result.stderr}")
                return {"_status": 1, "_msg": f"ng_detect程序启动失败: {result.stderr}"}
                
        except Exception as e:
            logger.error(f"启动二层模式时发生异常: {str(e)}")
            return {"_status": 1, "_msg": f"启动二层模式时发生异常: {str(e)}"}
    
    def stop_layer2_mode(self):
        """停止二层模式"""
        try:
            # 停止监控线程
            if self.is_monitoring:
                self.is_monitoring = False
                logger.info("正在停止配置监控线程")
                
                # 等待线程结束
                if self.monitor_thread and self.monitor_thread.is_alive():
                    self.monitor_thread.join(timeout=10)
                    logger.info("配置监控线程已停止")
            
            # 停止ng_detect程序
            try:
                # 查找并终止ng_detect进程
                result = subprocess.run(
                    ["pkill", "-f", Config.ng_detect_app_path],
                    capture_output=True,
                    text=True
                )
                if result.returncode == 0:
                    logger.info("ng_detect程序已停止")
                else:
                    logger.warning("停止ng_detect程序时没有找到相关进程")
            except Exception as e:
                logger.error(f"停止ng_detect程序时发生异常: {str(e)}")
            
            return {"_status": 0, "_msg": "二层模式已停止"}
            
        except Exception as e:
            logger.error(f"停止二层模式时发生异常: {str(e)}")
            return {"_status": 1, "_msg": f"停止二层模式时发生异常: {str(e)}"}
    
    def start_layer3_mode(self):
        """启动三层模式"""
        try:
            # 1. 获取所有配置参数
            config_params = self.config_manager.get_all_param()
            
            # 检查是否有配置参数
            if not config_params:
                logger.error("配置参数为空，无法启动三层模式")
                return {"_status": 1, "_msg": "配置参数为空，无法启动三层模式"}
            
            logger.info(f"获取到配置参数: {config_params}")
            
            # 2. 参数映射：将get_all_param()中的参数名映射到config_manager需要的参数名
            param_mapping = {
                'gnbSctp_IP': '__GNB_IP__',
                'amfSctp_IP': '__AMF_IP__', 
                'upf_IP': '__UPF_IP__',
                'mcc': '__MCC__',
                'mnc': '__MNC__',
                'tac': '__TAC__'
            }
            
            # 3. 根据映射关系构建更新参数
            mapped_params = {}
            for config_param, manager_param in param_mapping.items():
                if config_param in config_params and config_params[config_param]:
                    mapped_params[manager_param] = config_params[config_param]
            
            logger.info(f"映射后的参数: {mapped_params}")
            
            # 4. 根据映射后的参数更新config_manager
            update_results = self.config_manager.update_params(mapped_params)
            
            # 5. 检查更新结果
            failed_params = [param for param, success in update_results.items() if not success]
            if failed_params:
                logger.warning(f"以下参数更新失败: {failed_params}")
                # 继续执行，因为部分参数更新失败不应该阻止启动
            
            # 6. 执行启动脚本
            logger.info("开始执行启动脚本")
            script_result = execute_script(Config.start_script_path)
            
            if script_result.get("_status") == 0:
                logger.info("三层模式启动成功")
                return {"_status": 0, "_msg": "三层模式启动成功"}
            else:
                logger.error(f"启动脚本执行失败: {script_result.get('_msg', '未知错误')}")
                return {"_status": 1, "_msg": f"启动脚本执行失败: {script_result.get('_msg', '未知错误')}"}
                
        except Exception as e:
            logger.error(f"启动三层模式时发生异常: {str(e)}")
            return {"_status": 1, "_msg": f"启动三层模式时发生异常: {str(e)}"}
    
    def stop_layer3_mode(self):
        """停止三层模式"""
        try:
            logger.info("开始停止三层模式")
            
            # 执行停止脚本
            script_result = execute_script(Config.stop_script_path)
            
            if script_result.get("_status") == 0:
                logger.info("三层模式停止成功")
                return {"_status": 0, "_msg": "三层模式停止成功"}
            else:
                logger.error(f"停止脚本执行失败: {script_result.get('_msg', '未知错误')}")
                return {"_status": 1, "_msg": f"停止脚本执行失败: {script_result.get('_msg', '未知错误')}"}
                
        except Exception as e:
            logger.error(f"停止三层模式时发生异常: {str(e)}")
            return {"_status": 1, "_msg": f"停止三层模式时发生异常: {str(e)}"}
    
    def handle_device_command(self, params):
        """处理设备命令"""
        settype = params.get('settype')
        setbts = params.get('setbts')
        
        if setbts not in (1, 2) or settype not in (1, 2):
            return {"_status": 1, "_msg": "setbts或settype参数错误"}
        
        # 如果setbts==1,settype==1，启动二层模式
        if setbts == 1 and settype == 1:
            return self.start_layer2_mode()
        # 如果setbts==2,settype==2，停止二层模式
        elif setbts == 2 and settype == 1:
            return self.stop_layer2_mode()
        elif setbts == 1 and settype == 2:
            # 启动三层模式，执行前config.get_all_param()必须有值，根据这些值去更新config_manager.set_param_value,更新成功后执行execute_script(Config.start_script_path)
            return self.start_layer3_mode()
        elif setbts == 2 and settype == 2:
            # 三层模式停止 执行execute_script(Config.stop_script_path)
            return self.stop_layer3_mode()
        else:
            return {"_status": 0, "_msg": f"设备模式设置成功: setbts={setbts}, settype={settype}"}
    
    def get_status(self):
        """获取设备状态"""
        status = {
            "is_monitoring": self.is_monitoring,
            "thread_alive": self.monitor_thread.is_alive() if self.monitor_thread else False
        }
        return {"_status": 0, "_msg": "获取状态成功", "data": status}
